FreeRTOS 任务的状态
在xTaskCreate函数创建任务时,即为任务赋予了优先级。可以使用vTaskPrioritySet函数来修改任务的优先级,它的第一个参数是任务句柄、第二个参数是优先级,这个函数必须在调度器启动之后才能调用。相应的,uxTaskPriority函数返回一个任务的优先级。
1#include <task.h>
2void vTaskPrioritySet(TaskHandle_t xTask,UBaseType_t uxNewPriority);
3
4UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask);
5//返回任务的优先级对于优先级相同的任务,FreeRTOS采用时间片轮询调度,每个任务轮流执行一段微小的时间。下面这段代码创建两个优先级相同的任务打印串口消息:
1#include <stm32f4xx.h>
2#include <FreeRTOS.h>
3#include <task.h>
4#include <uart.h>
5
6void task1(void* args);
7void task2(void* args);
8
9int main()
10{
11 //配置USART1
12 USART1_Config();
13 //创建任务
14 TaskHandle_t h1,h2;
15 xTaskCreate(task1,"task1",configMINIMAL_STACK_SIZE,"hello\n",1,&h1);
16 xTaskCreate(task2,"task2",configMINIMAL_STACK_SIZE,"world\n",1,&h2);
17
18 //开启任务调度
19 vTaskStartScheduler();
20 while(1);
21}
22
23
24void task1(void* args)
25{
26 int i = 0;
27 while(1)
28 {
29 //循环5次后删除自己
30 if(i >= 5)
31 {
32 vTaskDelete(NULL);
33 }
34 //打印参数
35 USART_printf(USART1,args);
36 i++;
37 }
38}
39
40void task2(void* args)
41{
42 int i = 0;
43 while(1)
44 {
45 //循环10次后删除自己
46 if(i >= 10)
47 {
48 vTaskDelete(NULL);
49 }
50 //打印参数
51 USART_printf(USART1,args);
52 i++;
53 }
54}对于优先级不同的任务,FreeRTOS采用抢占式调度,高优先级的任务优先执行。将上面代码中的task1优先级设为2,task1会优先执行:
1#include <stm32f4xx.h>
2#include <FreeRTOS.h>
3#include <task.h>
4#include <uart.h>
5
6void task1(void* args);
7void task2(void* args);
8
9int main()
10{
11 //配置USART1
12 USART1_Config();
13 //创建任务
14 TaskHandle_t h1,h2;
15 xTaskCreate(task1,"task1",configMINIMAL_STACK_SIZE,"hello\n",2,&h1);
16 xTaskCreate(task2,"task2",configMINIMAL_STACK_SIZE,"world\n",1,&h2);
17 //开启任务调度
18 vTaskStartScheduler();
19 while(1);
20}
21
22
23void task1(void* args)
24{
25 int i = 0;
26 while(1)
27 {
28 //循环5次后删除自己
29 if(i >= 5)
30 {
31 vTaskDelete(NULL);
32 }
33 //打印参数
34 USART_printf(USART1,args);
35 i++;
36 }
37}
38
39void task2(void* args)
40{
41 int i = 0;
42 while(1)
43 {
44 //循环10次后删除自己
45 if(i >= 10)
46 {
47 vTaskDelete(NULL);
48 }
49 //打印参数
50 USART_printf(USART1,args);
51 i++;
52 }
53}FreeRTOS中任务存在4种状态:运行、就绪、阻塞和挂起。调度器总是让运行和就绪状态的任务中,优先级最高的任务进入运行状态。
| 状态 | 说明 |
|---|---|
| 运行状态(Running) | 正在运行的任务处于运行状态 |
| 就绪状态(Ready) | 可以运行但没有运行的任务处于就绪状态 |
| 阻塞状态(Blocked) | 等待某一事件而不能运行的任务处于阻塞状态 |
| 挂起状态(Suspended) | 调用vTaskSuspend挂起的任务处于挂起状态 |
运行状态的任务可以通过调用阻塞函数进入阻塞状态,阻塞解除的事件可以让阻塞状态的任务进入就绪状态,vTaskSuspend函数让任务进入挂起状态,vTaskResume函数让挂起的任务进入就绪状态。
vTaskDelay是一个阻塞函数,它让任务进入阻塞状态等待一个定时事件,它的参数是定时事件的延时时间(周期数)。当定时时间到达,就会产生定时事件,让任务进入就绪状态。
1#include <task.h>
2void vTaskDelay(const TickType_t xTicksToDelay);宏portTICK_RATE_MS表示每毫秒的周期数,用期望延时的毫秒数除以她可以得到相应的周期数,例如vTaskDelay(1000/portTICK_RATE_MS)延时1000毫秒。
仍然让task1的优先级高于task2,在task1中调用vTaskDelay阻塞,在task1阻塞期间,task2是优先级最高的任务,因此运行task2:
1#include <stm32f4xx.h>
2#include <FreeRTOS.h>
3#include <task.h>
4#include <uart.h>
5
6void task1(void* args);
7void task2(void* args);
8
9int main()
10{
11 //配置USART1
12 USART1_Config();
13 //创建任务
14 TaskHandle_t h1,h2;
15 xTaskCreate(task1,"task1",configMINIMAL_STACK_SIZE,"hello\n",2,&h1);
16 xTaskCreate(task2,"task2",configMINIMAL_STACK_SIZE,"world\n",1,&h2);
17 //开启任务调度
18 vTaskStartScheduler();
19 while(1);
20}
21
22
23void task1(void* args)
24{
25 int i = 0;
26 //阻塞1000ms
27 vTaskDelay(1000/portTICK_RATE_MS);
28 while(1)
29 {
30 //循环5次后删除自己
31 if(i >= 5)
32 {
33 vTaskDelete(NULL);
34 }
35 //打印参数
36 USART_printf(USART1,args);
37 i++;
38 }
39}
40
41void task2(void* args)
42{
43 int i = 0;
44 while(1)
45 {
46 //循环10次后删除自己
47 if(i >= 10)
48 {
49 vTaskDelete(NULL);
50 }
51 //打印参数
52 USART_printf(USART1,args);
53 i++;
54 }
55}挂起状态的任务对于调度器而言是不可见的。vTaskSuspend让任务进入挂起状态,vTaskResume让挂起的任务进入就绪状态,它们的参数都是要操作任务的句柄。
1#include <task.h>
2void vTaskSuspend(TaskHandle_t xTaskToSuspend);
3void vTaskResume(TaskHandle_t xTaskToResume);